package com.dianpingmedia.wifitz.read.usb;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.dianpingmedia.wifitz.read.listener.IReader;
import com.dianpingmedia.wifitz.read.listener.OnOutputListener;
import com.dianpingmedia.wifitz.read.serial.SerialPortManager;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.SerialInputOutputManager;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static android.content.Context.USB_SERVICE;

/**
 * @author zsc
 * @create 2018/6/19 0019
 * @Describe
 */
public class UsbReadManager implements IReader {
    private static WeakReference<Context> mWeakReContext;
    private UsbManager mUsbManager;
    private Handler mHandler = new Handler();
    private UsbSerialDriver mDriver;
    private byte[] tempByte;
    private static final int LF = 10;//换行符-asci
    private static final String TAG = "UsbReadManager";
    private static final String ACTION_USB_PERMISSION = "com.wch.wchusbdriver.USB_PERMISSION";
    private OnOutputListener mListener;
    private boolean isShowPermission = true;
    private Handler mLogHandler;

    private UsbReadManager() {

    }

    public static void init(Context context) {
        mWeakReContext = new WeakReference<Context>(context);
    }

    private static class Holder {
        private static final UsbReadManager mInstance = new UsbReadManager();

        private static UsbReadManager newInstance() {
            return mInstance;
        }
    }

    public static UsbReadManager getInstance() {
        return UsbReadManager.Holder.newInstance();
    }


    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                isShowPermission = intent.getBooleanExtra("permission", false);
                if (isShowPermission) {
                    sendLog("授权通过");
                    stop();
                    start(2);
                } else {
                    stop();
                    sendLog("您拒绝了USB读写权限");
                    Toast.makeText(context, "您拒绝了USB读写权限", Toast.LENGTH_LONG).show();
                }
                Log.d(TAG, action);
            }
        }
    };

    public void start(int retryTimes) {
        initUsb(retryTimes);
    }

    public void stop() {
        try {
            //释放驱动资源
            if (mDriver != null)
                mDriver.close();
            mWeakReContext.get().unregisterReceiver(mUsbReceiver);
            mHandler.removeCallbacksAndMessages(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void reboot() {
        stop();
        start(2);
    }

    @Override
    public void setHandler(Handler handler) {
        mLogHandler = handler;
    }

    private void initUsb(int retryCount) {
        if (mUsbManager == null)
            mUsbManager = (UsbManager) mWeakReContext.get().getSystemService(USB_SERVICE);
        //从设备列表中获取驱动（若用户未选择软件为启动软件，驱动获取则为空）
        Iterator<UsbDevice> iterator = mUsbManager.getDeviceList().values().iterator();

        if (!iterator.hasNext()) {
            sendLog("usb设备为空");
            return;
        }
        while (iterator.hasNext()) {
            UsbDevice usbDevice = iterator.next();
            if (usbDevice.getProductId() == 60000 && usbDevice.getVendorId() == 4292) {
                if (mUsbManager.hasPermission(usbDevice)) {
                    //进行USB通信
                    sendLog("进行USB通信");
                    usbConnec(usbDevice, retryCount);
                } else {
                    sendLog("需要请求授权");
                    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
                    mWeakReContext.get().registerReceiver(mUsbReceiver, filter);
                    //请求usb权限
                    PendingIntent mPendingIntent = PendingIntent.getBroadcast(mWeakReContext.get(), 0, new Intent(ACTION_USB_PERMISSION), 0);
                    ((UsbManager) mWeakReContext.get().getSystemService(USB_SERVICE)).requestPermission(usbDevice, mPendingIntent);
                }
            }
        }
    }


    /**
     * 返回设备是否可用
     *
     * @param mDevice
     * @return
     */
    private boolean checkDeviceInterface(UsbDevice mDevice) {
        // 一般来说一个设备都是一个接口，你可以通过getInterfaceCount()查看接口的个数
        // 这个接口上有两个端点，分别对应OUT 和 IN
        if (mDevice.getInterfaceCount() == 0) {
            return false;
        }
        UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
        if (dataIface.getEndpointCount() < 2) {//至少存在两个端点,供读写
            return false;
        }
        return true;

    }


    /**
     * 进行USB通信
     * 通信的过程不能在UI线程中进行
     *
     * @param usbDevice
     */
    private void usbConnec(UsbDevice usbDevice, final int retryCount) {
        List<UsbSerialDriver> mDriverList = UsbSerialProber.probeSingleDevice(mUsbManager, usbDevice);
        if (mDriverList == null || mDriverList.size() == 0) {
            sendLog("mDriverList=null");
            return;
        } else {
            mDriver = mDriverList.get(0);
        }
        //检查串口操作接口是否存在
        if (!checkDeviceInterface(usbDevice)) {
            if (retryCount <= 1) {
                return;
            }
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    initUsb(retryCount - 1);
                }
            }, 500);
            return;
        }
        try {
            mDriver.open();////打开驱动
            mDriver.setParameters(115200, 8, UsbSerialDriver.STOPBITS_2,
                    UsbSerialDriver.PARITY_NONE);////给驱动设置参数
            //开启线程池进行通信
            ExecutorService mExecutor = Executors.newSingleThreadExecutor();
            SerialInputOutputManager mSerialIoManager =
                    new SerialInputOutputManager(mDriver, new SerialInputOutputManager.Listener() {
                        @Override
                        public void onNewData(final byte[] bytes) {//驱动返回内容
                            String msg = dealUsbMessage(bytes);
                            if (TextUtils.isEmpty(msg))
                                return;
                            mListener.onSuccess(msg);
                        }

                        @Override
                        public void onRunError(final Exception e) {
                            mListener.onFail(e.getLocalizedMessage());
                        }
                    });
            mExecutor.submit(mSerialIoManager);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 根据换行符字节来 处理数据
     *
     * @param data
     * @return 返回完整的数据(以换行结尾)
     */
    private String dealUsbMessage(byte[] data) {

        if (data == null)
            return null;
        //        MyLog.w(TAG, byteToString(data));
        long start = System.currentTimeMillis();
        //处理返回字节
        //加上上次剩余字节，一同处理
        //截取至数组最后一个换行符字节解析，其余的添加至tempByte
        int lastLF = -1;
        final int lenData = data == null ? 0 : data.length;
        final int lenTem = tempByte == null ? 0 : tempByte.length;
        //寻找data中最后一个换行符

        int i = lenData - 1;
        while (i >= 0) {
            if (data[i] == LF) {
                lastLF = i;
                break;
            }
            --i;
        }
        //有效數據
        String msg = null;

        //缓存长度为0，且byte[]data已换行符结尾，则数据可以解析
        if (lenTem == 0 && lastLF == lenData) {
            msg = byteToString(data);
            //            MyLog.v(TAG, "temNull ----msg = " + msg);
        } else if (lastLF >= 0) {//含换行符且换行符不在结尾
            //生成新的字節數組
            byte[] strByte = new byte[lenTem + lastLF + 1];

            if (lenTem > 0)
                System.arraycopy(tempByte, 0, strByte, 0, lenTem);
            System.arraycopy(data, 0, strByte, lenTem, lastLF + 1);
            msg = byteToString(strByte);
            //            MyLog.v(TAG, "tem l ++++ msg = " + msg);
        }
        //生成新的tempByte;
        if (lastLF >= 0) {
            tempByte = new byte[lenData - lastLF - 1];
            tempByte = Arrays.copyOfRange(data, lastLF, lenData);
        } else {

            byte[] newByte = new byte[lenData + lenTem];

            if (lenTem > 0)
                System.arraycopy(tempByte, 0, newByte, 0, lenTem);
            System.arraycopy(data, 0, newByte, lenTem, lenData);
            tempByte = newByte;
        }
        //        MyLog.v(TAG, "tem  >>>> " + byteToString(tempByte));
        return deleteData(msg);
    }

    private String byteToString(byte[] data) {
        try {
            return new String(data, "utf-8");
        } catch (UnsupportedEncodingException e) {
            return new String(data);
        } catch (NullPointerException e) {
            return "";
        }
    }


    private String deleteData(String msg) {
        if (TextUtils.isEmpty(msg))
            return msg;
        String[] lineStrArr = msg.split("\n");
        if (lineStrArr.length > 0) {
            int startIndex = 1;
            String lineStr = lineStrArr[0];
            if (TextUtils.isEmpty(lineStr)) {
                try {
                    lineStr = lineStrArr[1];
                } catch (Exception e) {
                    return msg;
                }
                startIndex = 2;
            }
            //            String[] dataArr = lineStr.split("\\|");
            //            if (dataArr.length > 0 && (dataArr.length < 5 || dataArr[0].length() != 17)) {
            StringBuffer sb = new StringBuffer();
            //Log.i("数据", "丢弃" + lineStrArr[startIndex - 1]);
            for (int i = startIndex; i < lineStrArr.length; i++) {//丢弃第一行
                sb.append(lineStrArr[i] + "\n");
            }
            return sb.toString();
        }
        return msg;
    }


    public void addOnOutputListener(OnOutputListener listener) {
        this.mListener = listener;
    }


    private void sendLog(String log) {
        if (!TextUtils.isEmpty(log)) {
            Log.i(TAG, log);
            if (mLogHandler != null) {
                Message obtain = Message.obtain();
                obtain.what = 0;
                obtain.obj = log;
                mLogHandler.sendMessage(obtain);
            }
        }
    }
}
